home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue46 / packages / AppSupportU.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-05-04  |  7.6 KB  |  304 lines

  1. unit AppSupportU;
  2.  
  3. interface
  4.  
  5. uses
  6.   Classes, Windows, SysUtils, Forms;
  7.  
  8. type
  9.   PPackageRec = ^TPackageRec;
  10.   TPackageRec = record
  11.     FileName,
  12.     Description: String;
  13.     Module: HModule;
  14.     Group: Integer;
  15.   end;
  16.  
  17.   EPackageLoadError = class(EPackageError);
  18.  
  19. var
  20.   PackageList: TList;
  21.  
  22. //Registration routine for adding pages to the page control
  23. procedure InternalRegisterPages(Group: Integer; const Page: String; PageForms: array of TForm);
  24. procedure LoadPage(Group: Integer; const Page: String; PageForm: TForm);
  25. procedure UnloadPages(Group: Integer);
  26.  
  27. //Routines used for package group management
  28. function NewAppGroup: Integer;
  29. procedure FreeAppGroup(Group: Integer);
  30.  
  31. //Routines used for package management
  32. procedure InitializePackageSupport;
  33. procedure FinalizePackageSupport;
  34.  
  35. procedure LoadPackagesStoredInRegistry;
  36. procedure StorePackagesInRegistry;
  37.  
  38. function LoadCustomPackage(const Name: string): HModule;
  39. procedure UnloadCustomPackage(PackageModule: HModule);
  40.  
  41. procedure FormatPackagesAsDisplayList(List: TStrings);
  42.  
  43. implementation
  44.  
  45. uses
  46.   Registry, Dialogs, ComCtrls, CommonHookU, AppMainFormU;
  47.  
  48. type
  49.   PPageFormRec = ^TPageFormRec;
  50.   TPageFormRec = record
  51.     Group: Integer;
  52.     PageForm: TForm;
  53.     TabSheet: TTabSheet;
  54.   end;
  55.  
  56. var
  57.   PageFormList: TList = nil;
  58.  
  59. procedure InternalRegisterPages(Group: Integer; const Page: String; PageForms: array of TForm);
  60. var
  61.   Loop: Integer;
  62. begin
  63.   for Loop := Low(PageForms) to High(PageForms) do
  64.     LoadPage(Group, Page, PageForms[Loop])
  65. end;
  66.  
  67. procedure LoadPage(Group: Integer; const Page: String; PageForm: TForm);
  68. var
  69.   P: PPageFormRec;
  70. begin
  71.   if PageFormList = nil then
  72.     PageFormList := TList.Create;
  73.   New(P);
  74.   P.Group := CurrentGroup;
  75.   P.PageForm := PageForm;
  76.   P.TabSheet := TTabSheet.Create(nil);
  77.   PageFormList.Insert(0, P);
  78.   P.TabSheet.Parent := MainForm.PageControl;
  79.   P.TabSheet.PageControl := MainForm.PageControl;
  80.   P.TabSheet.Caption := Page;
  81.   MainForm.PageControl.ActivePage := P.TabSheet;
  82.   with P.PageForm do
  83.   begin
  84.     Hide;
  85.     Left := 0;
  86.     Top := 0;
  87.     BorderStyle := bsNone;
  88.     Parent := P.TabSheet;
  89.     WindowState := wsMaximized;
  90.     Show
  91.   end;
  92. end;
  93.  
  94. procedure UnloadPages(Group: Integer);
  95. var
  96.   I: Integer;
  97.   P: PPageFormRec;
  98.   PageCtl: TPageControl;
  99. begin
  100.   if not Assigned(PageFormList) then
  101.     Exit;
  102.   I := PageFormList.Count - 1;
  103.   while I > -1 do
  104.   begin
  105.     P := PageFormList[I];
  106.     if P.Group = Group then
  107.     begin
  108.       PageCtl := P.TabSheet.PageControl;
  109.       //Switch to a page that we are not removing
  110.       if Assigned(PageCtl) and (PageCtl.ActivePage = P.TabSheet) then
  111.         PageCtl.SelectNextPage(False);
  112.       P.PageForm.Free;
  113.       P.TabSheet.Free;
  114.       PageFormList.Delete(I);
  115.       Dispose(P);
  116.     end;
  117.     Dec(I);
  118.   end;
  119. end;
  120.  
  121. //Package group management support
  122. var
  123.   AppGroupList: TBits = nil;
  124.  
  125. function NewAppGroup: Integer;
  126. begin
  127.   if AppGroupList = nil then
  128.     AppGroupList := TBits.Create;
  129.   CurrentGroup := AppGroupList.OpenBit;
  130.   AppGroupList[CurrentGroup] := True;
  131.   Result := CurrentGroup;
  132. end;
  133.  
  134. procedure FreeAppGroup(Group: Integer);
  135. begin
  136.   //Destroy any forms that were created by this group
  137.   UnloadPages(Group);
  138.   //Free group number for later possible re-use
  139.   if (Group >= 0) and (Group < AppGroupList.Size) then
  140.     AppGroupList[Group] := False;
  141. end;
  142.  
  143. procedure InitializePackageSupport;
  144. begin
  145.   //Create package list
  146.   PackageList := TList.Create;
  147.   RegisterPagesProc := InternalRegisterPages
  148. end;
  149.  
  150. procedure FinalizePackageSupport;
  151. begin
  152.   //Unload packages
  153.   while PackageList.Count > 0 do
  154.     UnloadCustomPackage(PPackageRec(PackageList[0]).Module);
  155.   //Delete package list
  156.   PackageList.Free;
  157.   AppGroupList.Free;
  158.   //Free page control form list
  159.   PageFormList.Free
  160. end;
  161.  
  162. const
  163. {$ifdef Ver100}
  164.   RegPath = 'Software\Oblong\AppProject3';
  165. {$else}
  166.   RegPath = 'Software\Oblong\AppProject4';
  167. {$endif}
  168.   RegSection = 'Known Modules';
  169.  
  170. procedure LoadPackagesStoredInRegistry;
  171. var
  172.   Pkgs: TStrings;
  173.   Loop: Integer;
  174. begin
  175.   with TRegIniFile.Create(RegPath) do
  176.     try
  177.       Pkgs := TStringList.Create;
  178.       try
  179.         ReadSection(RegSection, Pkgs);
  180.         for Loop := 0 to Pkgs.Count - 1 do
  181.           LoadCustomPackage(Pkgs[Loop])
  182.       finally
  183.         Pkgs.Free
  184.       end
  185.     finally
  186.       Free
  187.     end
  188. end;
  189.  
  190. procedure StorePackagesInRegistry;
  191. var
  192.   Loop: Integer;
  193. begin
  194.   with TRegIniFile.Create(RegPath) do
  195.     try
  196.       EraseSection(RegSection);
  197.       for Loop := 0 to PackageList.Count - 1 do
  198.         with TPackageRec(PackageList[Loop]^) do
  199.           WriteString(RegSection, FileName, Description)
  200.     finally
  201.       Free
  202.     end;
  203. end;
  204.  
  205. procedure PackageInfoProc(const Name: string;
  206.   NameType: TNameType; Flags: Byte; Param: Pointer);
  207. type
  208.   TRegisterProc = procedure;
  209. var
  210.   RegisterProc: TRegisterProc;
  211.   UnitName, ProcName: String;
  212. const
  213. {$ifdef Ver100} //Delphi 3
  214.   ExportName = '%s.BLRegister@51F89FF7';
  215. {$else}
  216.   ExportName = '@%s@BLRegister$qqrv';
  217. {$endif}
  218. begin
  219.   if NameType = ntContainsUnit then
  220.   begin
  221.   {$ifdef Ver100} //Delphi 3
  222.     //Delphi 3 packages don't use name-mangling
  223.     //Unit names maintain their original case
  224.     UnitName := Name;
  225.   {$else}
  226.     //Delphi 4+ mangles names - the unit name is all
  227.     //lower case, with an initial capital letter
  228.     UnitName := LowerCase(Name);
  229.     if Length(UnitName) > 0 then
  230.       UnitName[1] := UpCase(UnitName[1]);
  231.   {$endif}
  232.     ProcName := Format(ExportName, [UnitName]);
  233.     @RegisterProc := GetProcAddress(PPackageRec(Param).Module, PChar(ProcName));
  234.     if Assigned(RegisterProc) then
  235.       try
  236.         RegisterProc
  237.       except
  238.         on E: Exception do
  239.           ShowMessageFmt('Error %s registering %s package',
  240.             [E.ClassName, PPackageRec(Param).FileName])
  241.       end
  242.   end
  243. end;
  244.  
  245. //Simple wrapper for SysUtils.LoadPackage which also adds to the package list
  246. function LoadCustomPackage(const Name: String): HModule;
  247. var
  248.   P: PPackageRec;
  249.   Loop, PackageFlags: integer;
  250. begin
  251.   for Loop := 0 to PackageList.Count - 1 do
  252.     with TPackageRec(PackageList[Loop]^) do
  253.       if AnsiCompareFileName(Name, FileName) = 0 then
  254.         raise EPackageLoadError.CreateFmt(
  255.           'Package already loaded:'#13'  %s'#13'  %s',
  256.           [FileName, Description]);
  257.   Result := LoadPackage(Name);
  258.   New(P);
  259.   P.Module := Result;
  260.   P.FileName := Name;
  261.   P.Description := GetPackageDescription(PChar(Name));
  262.   CurrentGroup := NewAppGroup;
  263.   P.Group := CurrentGroup;
  264.   PackageList.Add(P);
  265.   GetPackageInfo(P.Module, P, PackageFlags, PackageInfoProc);
  266. end;
  267.  
  268. //Simple wrapper for SysUtils.UnloadPackage
  269. //which also removes from the package list
  270. procedure UnloadCustomPackage(PackageModule: HModule);
  271. var
  272.   Loop: Integer;
  273. begin
  274.   for Loop := 0 to PackageList.Count do
  275.     if PPackageRec(PackageList[Loop]).Module = PackageModule then
  276.     begin
  277.       FreeAppGroup(PPackageRec(PackageList[Loop]).Group);
  278.       UnloadPackage(PackageModule);
  279.       Dispose(PackageList[Loop]);
  280.       PackageList.Delete(Loop);
  281.       Break
  282.     end
  283. end;
  284.  
  285. //Code to take the package list and extract a displayable subset
  286. //The target TStrings object has the descriptions added,
  287. //as well as the module handles (in the Objects array)
  288. procedure FormatPackagesAsDisplayList(List: TStrings);
  289. var
  290.   Loop: Integer;
  291. begin
  292.   List.BeginUpdate;
  293.   try
  294.     List.Clear;
  295.     for Loop := 0 to PackageList.Count - 1 do
  296.       with TPackageRec(PackageList[Loop]^) do
  297.         List.AddObject(Description, TObject(Module))
  298.   finally
  299.     List.EndUpdate
  300.   end
  301. end;
  302.  
  303. end.
  304.